﻿using Fast;
using Fast.Reflection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace Microsoft.Extensions.DependencyInjection
{
    /// <summary>
    /// 依赖注入服务扩展类
    /// </summary>
    [SkipScan]
    public static class DependencyInjectionServiceCollectionExtensions
    {
        /// <summary>
        /// 创建代理方法
        /// </summary>
        private static readonly MethodInfo DispatchProxyCreateMethod;

        static DependencyInjectionServiceCollectionExtensions()
        {
            DispatchProxyCreateMethod = typeof(AspectDispatchProxy).GetMethod(nameof(AspectDispatchProxy.Create));
        }

        /// <summary>
        /// 添加依赖注入接口
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <returns>服务集合</returns>
        public static IServiceCollection AddDependencyInjection(this IServiceCollection services)
        {
            // 添加内部依赖注入扫描拓展
            services.AddInnerDependencyInjection();

            return services;
        }

        /// <summary>
        /// 添加接口代理
        /// </summary>
        /// <typeparam name="TDispatchProxy">代理类</typeparam>
        /// <typeparam name="TIDispatchProxy">被代理接口依赖</typeparam>
        /// <param name="services">服务集合</param>
        /// <returns>服务集合</returns>
        public static IServiceCollection AddDispatchProxyForInterface<TDispatchProxy, TIDispatchProxy>(this IServiceCollection services)
            where TDispatchProxy : AspectDispatchProxy, IDispatchProxy
            where TIDispatchProxy : class
        {
            // 代理依赖接口类型
            var proxyType = typeof(TDispatchProxy);
            var typeDependency = typeof(TIDispatchProxy);

            // 获取所有的代理接口类型
            var dispatchProxyInterfaceTypes = App.Types.Where(u => typeDependency.IsAssignableFrom(u) && u.IsInterface && u != typeDependency);

            // 注册代理类型
            foreach (var interfaceType in dispatchProxyInterfaceTypes)
            {
                AddDispatchProxy(services, default, proxyType, interfaceType, false);
            }

            return services;
        }


        /// <summary>
        /// 添加扫描注入
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <returns>服务集合</returns>
        private static IServiceCollection AddInnerDependencyInjection(this IServiceCollection services)
        {
            // 查找所有需要依赖注入的类型
            var injectTypes = App.Types
                .Where(u => (typeof(IDependencyBase).IsAssignableFrom(u) || u.IsDefined(typeof(DependencyAttribute))) && u.IsClass && !u.IsInterface && !u.IsAbstract).Distinct();

            var projectAssemblies = App.Assemblies;
            var lifetimeInterfaces = new[] { typeof(ITransientDependency), typeof(IScopedDependency), typeof(ISingletonDependency) };

            // 执行依赖注入
            foreach (var type in injectTypes)
            {
                // 获取注册方式
                var dependencyAttribute = !type.IsDefined(typeof(DependencyAttribute)) ? null : type.GetCustomAttribute<DependencyAttribute>();

                var interfaces = type.GetInterfaces();

                var serviceInterfaces = interfaces.Where(i => i != typeof(IDependencyBase)
                        && !lifetimeInterfaces.Contains(i)
                        && (
                        (!type.IsGenericType && !i.IsGenericType)) ||
                        (type.IsGenericType && i.IsGenericType && type.GetGenericArguments().Length == i.GetGenericArguments().Length)
                        );
                Func<ServiceLifetime?> lifetimeFunc = () =>
                {
                    var dependencyType = interfaces.Last(u => lifetimeInterfaces.Contains(u));
                    return GetServiceLifetime(dependencyType);
                };
                //获取生命周期
                var lifetime = dependencyAttribute != null ? dependencyAttribute.Lifetime : lifetimeFunc();
                //注册服务
                RegisterService(services, serviceInterfaces, type, lifetime);
            }

            return services;
        }

        /// <summary>
        /// 注册服务
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="serviceInterfaces">能被注册的接口</param>
        /// <param name="implementationType">类型</param>
        /// <param name="lifetime">生命周期</param>
        private static void RegisterService(IServiceCollection services, IEnumerable<Type> serviceInterfaces, Type implementationType, ServiceLifetime? lifetime)
        {
            if (lifetime != null)
            {
                foreach (var serviceInterface in serviceInterfaces)
                {
                    var serviceDescriptor = ServiceDescriptor.Describe(serviceInterface, implementationType, lifetime.Value);
                    services.TryAdd(serviceDescriptor);
                }
            }
        }
        
        /// <summary>
        /// 获取服务生命周期
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private static ServiceLifetime? GetServiceLifetime(Type type)
        {
            if (typeof(ITransientDependency).GetTypeInfo().IsAssignableFrom(type))
            {
                return ServiceLifetime.Transient;
            }

            if (typeof(ISingletonDependency).GetTypeInfo().IsAssignableFrom(type))
            {
                return ServiceLifetime.Singleton;
            }

            if (typeof(IScopedDependency).GetTypeInfo().IsAssignableFrom(type))
            {
                return ServiceLifetime.Scoped;
            }

            return null;
        }

        /// <summary>
        /// 创建服务代理
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="type">拦截的类型</param>
        /// <param name="proxyType">代理类型</param>
        /// <param name="interface">代理接口</param>
        /// <param name="hasTarget">是否有实现类</param>
        private static void AddDispatchProxy(IServiceCollection services, Type type, Type proxyType, Type @interface, bool hasTarget = true)
        {
            if (proxyType == null) return;

            // 注册服务
            services.AddTransient(@interface, provider =>
            {
                dynamic proxy = DispatchProxyCreateMethod.MakeGenericMethod(@interface, proxyType).Invoke(null, null);

                if (hasTarget)
                {
                    proxy.Target = provider.GetService(type);
                }

                return proxy;
            });
        }
    }
}
